Skip to content

[codex] fix Claude auth probe and state sync locking#441

Merged
skulidropek merged 21 commits into
ProverCoderAI:mainfrom
skulidropek:pr-440
Jul 2, 2026
Merged

[codex] fix Claude auth probe and state sync locking#441
skulidropek merged 21 commits into
ProverCoderAI:mainfrom
skulidropek:pr-440

Conversation

@skulidropek

@skulidropek skulidropek commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

  • harden Claude OAuth probes so tokens are stored in 0600 files and passed to Docker via --env-file, never via stdout or Docker argv; add writable tmpfs probe HOME
  • clean inherited Claude OAuth env in local smoke flows, tighten setup-token token extraction to real sk-ant-* tokens, and isolate local probe HOME from account settings
  • share Claude auth-method detection between API and lib, keep normalizing side effects in the CLI flow, and guard /auth/*/status account/path payloads to loopback clients
  • add stale state-lock reclaim with TTL metadata, remove sensitive state paths/raw remotes from state logs, and pass captured cwd through state lock/init flows
  • address app/CI CodeRabbit notes: reachable Bun install retries with process-group termination, runtime compose overlay regular-file validation, contextual compose errors, true/false fixture coverage, and Effect-style tests
  • update documented auth claude login --web parser/e2e coverage and follow-up auth claude status verification without token disclosure

Validation

  • bun run --cwd packages/auth-oauth test -- claude-docker-oauth.test.ts claude-local-smoke.test.ts claude-oauth-token.test.ts
  • bun run --cwd packages/lib test -- auth-claude-login.test.ts auth-claude-local.test.ts state-repo-auto-sync.test.ts
  • bun run --cwd packages/api test -- auth.test.ts auth-github-login-stream.test.ts
  • bun run --cwd packages/app test -- controller-compose.test.ts parser-auth.test.ts program-auth.test.ts actions-github-oauth.test.ts
  • bun run --cwd packages/auth-oauth typecheck
  • bun run --cwd packages/lib typecheck
  • bun run --cwd packages/api typecheck
  • bun run --cwd packages/app typecheck
  • bun run --cwd packages/openapi typecheck
  • bun run --cwd packages/lib lint:effect
  • bun run --cwd packages/api lint:effect (exit 0; existing warnings remain)
  • bun run --cwd packages/app lint:effect
  • git diff --check

Proof of fix

  • Причина: CodeRabbit warnings were valid across several boundaries: Claude OAuth secrets reached Docker argv/stdout, probes reused unsafe account or unwritable probe config, auth claude login --web/status coverage was incomplete, API status duplicated auth-method logic and exposed account metadata without locality checks, state repo locks could remain forever after a crash, compose validation missed isolated runtime overlays, and CI Bun retries could not run inside the job timeout.
  • Решение: OAuth probes now use temp env files with 0600 mode and tmpfs HOME; token extraction requires sk-ant-*; local and Docker probe envs are isolated; API status uses a shared read-only Claude detector plus loopback guard; state locks include reclaimable TTL metadata and sanitized logs; compose/runtime overlays are validated as regular files; CI retries fit the job timeout and terminate process groups; e2e/parser tests cover auth claude login --web followed by auth claude status.
  • Доказательство: targeted regression tests cover no-token stdout/argv rendering, env-file mode/content, stale env cleanup, strict token extraction, account-settings probe isolation, Claude status account/secret invariants, loopback classification, stale lock reclaim, auto-sync lock properties, runtime overlay directory rejection, build-skiller aliases, and documented Claude web login/status routing.

konard and others added 19 commits June 26, 2026 08:24
Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: ProverCoderAI#439
docker-git auth claude login created and persisted the OAuth token, then ran
a 'claude -p ping' probe and hard-failed (exit 1) on any non-zero probe exit,
discarding an otherwise successful login. Transient probe failures (network,
rate limit, token propagation delay) must not invalidate a saved token.

The probe failure is now logged as a warning, mirroring authClaudeStatus.

Adds a regression test asserting the token is persisted even when the probe
returns non-zero.

Fixes ProverCoderAI#439
Reject directory-valued docker-compose.gpu.yml before constructing docker compose arguments.

Proof of fix: tests/docker-git/controller-compose.test.ts failed before the stat check and now passes with the new directory-as-overlay regression.
Retry transient Bun dependency installation failures in CI setup before failing the job.

Proof of fix: CI job 84095018943 failed while downloading @effect/platform during bun install; local shell syntax and bun install --frozen-lockfile both pass after adding bounded retries.
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Добавлен пакет auth-oauth с Docker- и локальными Claude OAuth-флоу, общий login flow с warning-поведенем для probe, новый /auth/claude/status endpoint, и валидация controller compose overlay-файлов. Также обновлены CI, e2e, state-repo locking, версии пакетов и генерация plan-to-git Dockerfile.

Changes

Claude OAuth login flow and supporting package

Layer / File(s) Summary
Token utilities and tests
packages/auth-oauth/src/claude-oauth-token.ts, packages/auth-oauth/tests/claude-oauth-token.test.ts
Нормализация, редактирование, извлечение и классификация Claude OAuth-токена, с покрытием тестами.
Docker OAuth runner and CLI
packages/auth-oauth/src/claude-docker-oauth.ts, packages/auth-oauth/tests/claude-docker-oauth.test.ts
Docker-раннер для setup-token/probe, атомарная запись токена, рендер результата и CLI-режим.
Local smoke runner
packages/auth-oauth/src/claude-local-smoke.ts, packages/auth-oauth/tests/claude-local-smoke.test.ts
Локальные smoke-режимы env-token и setup-token с сохранением токена и probe.
Package entrypoint and workspace wiring
packages/auth-oauth/src/index.ts, packages/auth-oauth/package.json, packages/auth-oauth/tsconfig.json, pnpm-workspace.yaml, package.json, packages/api/Dockerfile, packages/lib/package.json
Ре-экспорты, манифесты, tsconfig и подключение нового workspace-пакета к сборке и тестам.
Shared login flow and local adapter
packages/lib/src/usecases/auth-claude-login-flow.ts, packages/lib/src/usecases/auth-claude-local.ts, packages/lib/src/usecases/auth.ts, packages/lib/tests/usecases/auth-claude-local.test.ts, packages/lib/tests/usecases/auth-claude-login-flow.test.ts
Общий login flow с warning вместо ошибки на probe failure и локальный адаптер поверх него.
auth-claude integration
packages/lib/src/usecases/auth-claude-oauth.ts, packages/lib/src/usecases/auth-claude.ts, .changeset/fix-claude-auth-login-probe.md, packages/lib/tests/usecases/auth-claude-login.test.ts
authClaudeLogin и authClaudeStatus используют общий flow и новый probe-auth контракт, сохраняя токен при неудачном probe.
E2E and CI wiring
scripts/e2e/auth-claude-login.sh, scripts/e2e/run-all.sh, scripts/e2e/_lib.sh, .github/workflows/check.yml
Новый e2e-сценарий и job для Claude login, с wrapper-логикой и включением в дефолтный набор кейсов.

Claude auth status API and routing

Layer / File(s) Summary
Status contract and OpenAPI schema
packages/api/src/api/contracts.ts, packages/api/src/api/openapi.ts, packages/openapi/openapi.json, packages/openapi/src/openapi-paths.ts, packages/api/tests/openapi.test.ts
Добавлен ClaudeAuthStatus, OpenAPI-схемы и маршрут GET /auth/claude/status, плюс обновления сгенерированных путей и тестов.
Status service and HTTP route
packages/api/src/services/auth.ts, packages/api/src/http.ts, packages/api/tests/auth.test.ts
Сервис читает Claude auth state из controller storage, а HTTP слой возвращает JSON по новому endpoint.
Client routing and command dispatch
packages/app/src/docker-git/api-client-auth.ts, packages/app/src/docker-git/api-client.ts, packages/app/src/docker-git/program-auth.ts, packages/app/src/docker-git/program-unsupported.ts, packages/app/tests/docker-git/parser-auth.test.ts, packages/app/tests/docker-git/program-auth.test.ts
Docker-git клиент и маршрутизация команд поддерживают AuthClaudeStatus; unsupported-команды обновлены соответствующим образом.

Compose overlay validation in controller

Layer / File(s) Summary
Compose files module
packages/app/src/docker-git/controller-compose-files.ts
Модуль собирает compose args и валидирует extra/GPU overlay пути как обычные файлы.
Controller compose wiring
packages/app/src/docker-git/controller-compose.ts
Ре-экспорт compose helper-ов и добавление extraOverlayPath в resolved compose files.
Compose fixtures and overlay tests
packages/app/tests/docker-git/controller-compose-fixture.ts, packages/app/tests/docker-git/controller-compose.test.ts
Фикстуры и тесты для временных root-ов, extra overlay и rejection директории вместо файла.

Infrastructure and support changes

Layer / File(s) Summary
State repo lock and sync behavior
packages/lib/src/usecases/state-repo/lock.ts, packages/lib/src/usecases/state-repo.ts, packages/lib/tests/usecases/state-repo-auto-sync.test.ts
Filesystem lock для state repo, проверка .git/index.lock, единое логирование auto-sync/auto-pull и тесты.
State repo initialization
packages/lib/src/usecases/state-repo/init.ts
Инициализация state repo, clone/fallback clone, remote setup и checkout logic.
CI install retry and plan-to-git patch source
.github/actions/setup/action.yml, packages/container/src/core/templates/dockerfile-prelude.ts, packages/container/tests/core/templates.test.ts
Retry для bun install и смена plan-to-git input с GitHub API JSON на patch-файл.
Version bumps and changelogs
packages/app/package.json, packages/app/CHANGELOG.md, packages/docker-git-session-sync/package.json, packages/docker-git-session-sync/CHANGELOG.md
Обновлены версии пакетов и changelog-записи.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant caller
  participant runClaudeLoginFlow
  participant token store
  participant probe

  caller->>runClaudeLoginFlow: capture token
  runClaudeLoginFlow->>token store: persistToken()
  runClaudeLoginFlow->>token store: normalizeStoredCredentials()
  runClaudeLoginFlow->>probe: probeToken()
  probe-->>runClaudeLoginFlow: exit code
  runClaudeLoginFlow->>token store: syncState()
  runClaudeLoginFlow-->>caller: result
Loading
sequenceDiagram
  participant client
  participant http.ts
  participant readClaudeAuthStatus
  participant controller storage

  client->>http.ts: GET /auth/claude/status?label=...
  http.ts->>readClaudeAuthStatus: label
  readClaudeAuthStatus->>controller storage: inspect auth files
  controller storage-->>readClaudeAuthStatus: status data
  readClaudeAuthStatus-->>http.ts: ClaudeAuthStatus
  http.ts-->>client: JSON response
Loading

Possibly related PRs

  • ProverCoderAI/docker-git#351: изменяет ту же логику сборки compose-файлов и resolveControllerComposeFiles, пересекающуюся с controller compose overlay change.
🚥 Pre-merge checks | ✅ 6 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Security Regression ⚠️ Warning readClaudeAuthStatus extracts email/displayName/account IDs and /auth/claude/status serves them over an unauthenticated API route. Remove account identity from the status payload or restrict the route to authenticated/localhost-only access before merging.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed Заголовок кратко и точно отражает основное изменение: исправление Claude auth probe и блокировки state sync.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Requirements Alignment ✅ Passed Изменения соответствуют описанию PR: маршрутизация/контракт /auth/claude/status, изоляция probe, state-lock и откат probe-failure покрыты тестами.
Description check ✅ Passed Описание подробное и по теме: есть summary, validation и proof of fix, но отсутствуют шаблонные секции Source TZ/Issues и Requirements Alignment.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/setup/action.yml:
- Around line 61-88: The retry logic in run_bun_install is effectively
unreachable because the surrounding build job can time out before the first
20-minute watchdog finishes. Update the action’s timeout handling so it fits
within the job’s actual timeout in the check workflow, either by reducing the
bun install watchdog/retry window or by aligning the job timeout higher; keep
the fix centered around run_bun_install and the retry loop in this action.
- Around line 63-74: Update the timeout handling in the setup action so the
watchdog kills the entire process group, not just the `bun install` parent PID.
In the `bun install --frozen-lockfile` block, start the install in its own
process group and make the timeout path send the termination signal to that
group, including any child processes spawned by lifecycle scripts. Keep the
existing `install_pid`, `timeout_pid`, and `wait` flow in the action, but change
the termination logic to target the full group.

In `@packages/app/src/docker-git/controller-compose-files.ts`:
- Around line 20-21: The error text in mapComposePathError is too specific to
docker-compose.yml, but this mapper is also used for extra and GPU overlay
paths. Update the error mapping in controller-compose-files so the message
includes the actual path/context being resolved, or split the mapper into
separate helpers for base and overlay resolution; make sure callers from the
compose path resolution flow pass the relevant overlay name or file type into
the mapper.

In `@packages/app/src/docker-git/controller-compose.ts`:
- Around line 246-248: The runtime overlay path in
resolveControllerRuntimeOverlayPath() still accepts any existing path, so add
the same stat(...).type === "File" validation used for the other overlays to
reject directories for docker-compose.isolated.yml as well. Update the runtime
overlay resolution flow in controller-compose.ts to fail early with a clear
error before docker compose is invoked, and add a regression test covering a
directory passed as the isolated runtime overlay.

In `@packages/app/tests/docker-git/controller-compose-fixture.ts`:
- Around line 119-128: The controller build skiller fixture arbitrary does not
cover the full DOCKER_GIT_CONTROLLER_BUILD_SKILLER contract, so add the missing
alias values to controllerBuildSkillerFixtureModeArbitrary in
controller-compose-fixture.ts. Update the fc.constantFrom set to include "true"
and "false" alongside undefined, "0", and "1", so the parser normalization path
for env aliases is exercised and regressions in the build-skiller mode handling
are caught.

In `@packages/auth-oauth/src/claude-docker-oauth.ts`:
- Around line 389-399: Remove all token emission from the Claude OAuth CLI
output, including the `renderClaudeDockerOauthResult` path and the related
stdout branch in the result-printing flow. Keep `printToken` as a no-op for
credentials and only print non-sensitive status/probe information, so no full
credential can ever reach shell history, CI logs, or downstream scripts. Locate
the affected logic in `renderClaudeDockerOauthResult` and the token-printing
handling around the CLI result output, and ensure the final output path never
includes `result.token` or any equivalent secret value.
- Around line 216-223: The OAuth token is being exposed both in the docker argv
and in stdout. In the docker command setup inside claude-docker-oauth.ts, stop
passing CLAUDE_CODE_OAUTH_TOKEN directly via args.push and move it to a secure
temporary env file or mounted file with restrictive permissions, then load it
inside the container. Also update renderClaudeDockerOauthResult so it never
prints result.token, removing the --print-token path entirely or making it a
no-op for token output.

In `@packages/auth-oauth/src/claude-local-smoke.ts`:
- Around line 78-87: buildClaudeLocalOauthEnv currently spreads the entire
baseEnv, so inherited OAuth variables can override the fresh token used by the
probe. Update buildClaudeLocalOauthEnv in claude-local-smoke.ts to strip any
preexisting OAuth-related env keys from baseEnv before setting
CLAUDE_CODE_OAUTH_TOKEN, especially DOCKER_GIT_CLAUDE_OAUTH_TOKEN, then keep the
explicit CLAUDE_CONFIG_DIR and HOME overrides. Apply the same env-cleanup logic
anywhere the probe env is constructed in the related smoke/probe path so the
child process only sees the newly captured token.

In `@packages/auth-oauth/src/claude-oauth-token.ts`:
- Around line 37-38: `extractClaudeOauthToken()` is too permissive and can treat
diagnostic text after the marker as a token; tighten the parsing in
`oauthTokenRegex`/`compactSection` so only strings matching the real OAuth token
shape are accepted, using `oauthLiveOutputTokenPrefix` as part of the
validation. Update the token extraction logic in `claude-oauth-token.ts` to
reject marker-only or marker-plus-text output, and add a regression test
covering `setup-token` output that contains the marker but no actual token so
`claude-docker-oauth.ts` never persists a false credential.

In `@packages/auth-oauth/tests/claude-local-smoke.test.ts`:
- Around line 62-92: Add a failing regression test in claude-local-smoke.test.ts
that covers the probe env token precedence bug: start from a base env containing
both DOCKER_GIT_CLAUDE_OAUTH_TOKEN and other vars, then assert
buildClaudeLocalOauthEnv (and the local probe flow if applicable) only preserves
the fresh token by setting CLAUDE_CODE_OAUTH_TOKEN and not inheriting the stale
docker-git token. Update envArbitrary or add a dedicated case so the property
test models both keys, and reference buildClaudeLocalOauthEnv plus
renderClaudeLocalOauthSmokeResult if needed to keep the smoke coverage aligned.
- Around line 94-174: The smoke tests in claude-local-smoke.test.ts are still
using async/await and Promise-style helpers, so convert each case to it.effect
with Effect.gen to match the repository’s other usecase tests. Update the
affected test bodies around runClaudeLocalOauthSmoke,
persistClaudeLocalOauthToken, readFile, and renderClaudeLocalOauthSmokeResult so
the setup, assertions, and probe/setup-token stubs are expressed through
Effect-based test flows instead of plain async functions.

In `@packages/lib/src/usecases/auth-claude-local.ts`:
- Around line 38-57: The local Claude OAuth probe currently reuses account-level
config via buildClaudeLocalEnv, so runClaudeLocalPingProbeExitCode still
inherits settings.json and session state from accountPath. Change the probe flow
to use a separate temporary Claude config directory for the ping command,
matching the isolation already used in the docker path, and keep accountPath
only for the real account data. Update buildClaudeLocalEnv and
runClaudeLocalPingProbeExitCode accordingly, and add a regression test that
exercises ClaudeLoginProbeFailed behavior when accountPath contains an existing
settings.json with bypassPermissions or similar login-policy settings.

In `@packages/lib/src/usecases/state-repo.ts`:
- Around line 145-148: The warning in state-repo’s auto-sync path is leaking an
absolute filesystem path through the `Effect.logWarning` message that references
`indexLockPath`. Update the log in `state-repo` to avoid printing user-specific
absolute paths; keep the diagnostic context but replace the interpolated path
with a sanitized reference such as `.git/index.lock` or a generic
repository-root alias.

In `@packages/lib/src/usecases/state-repo/lock.ts`:
- Around line 75-79: The lock repository logic currently reads cwd directly via
process.cwd(), which should be removed from product code. Update the state lock
flow in lock.ts, especially the Effect.gen block that calls resolveStateRoot, to
obtain cwd/root through an Effect service or an explicit parameter instead of
the global process. Keep resolveStateLockPath and the surrounding repository
logic unchanged, but wire the cwd source through the existing Effect runtime
boundary so the code remains testable and SHELL-compliant.
- Around line 20-45: The state lock in acquireStateFileLock/releaseStateFileLock
can remain forever if the process crashes before cleanup, because the
<root>.lock directory has no owner or expiry handling. Update the lock flow in
acquireStateFileLock and the withStateGitLock path to detect and reclaim stale
locks, for example by storing owner/heartbeat metadata and checking age or
liveness before treating the lock as busy, or by switching to a real system file
lock. Keep releaseStateFileLock as best-effort cleanup, but make lock
acquisition resilient to orphaned lock directories.

In `@packages/lib/tests/usecases/auth-claude-login-flow.test.ts`:
- Around line 93-96: The current test only covers normalizeClaudeOauthToken
directly and bypasses runClaudeLoginFlow, so it will miss regressions in the
boundary handling. Update the test in auth-claude-login-flow.test.ts to exercise
runClaudeLoginFlow with a captureToken containing surrounding
whitespace/newlines, and assert that persistToken and probeToken receive the
trimmed token value. Keep the check at the flow boundary using the
runClaudeLoginFlow/ensureClaudeOauthToken path rather than testing
normalizeClaudeOauthToken in isolation, and follow the test style conventions by
expressing the invariant with fc.property where appropriate.

In `@packages/lib/tests/usecases/state-repo-auto-sync.test.ts`:
- Around line 102-179: Current tests only cover two fixed auto-sync cases; add a
property-based test around autoSyncState to vary whether .git/index.lock exists
and the git exit codes. Use fc.property with the existing helpers like
withTempDir, withPatchedEnv, makeFakeExecutor, and isMutatingSyncGitCommand to
assert the invariants that index.lock implies zero mutating git commands and
that any git failure still leaves the state .lock file absent. Keep the existing
logging assertions where relevant, but move the core expectations into the
generated property cases so the behavior is checked across many combinations.

In `@scripts/e2e/auth-claude-login.sh`:
- Around line 117-142: The e2e in auth-claude-login.sh currently exercises the
non-web login path and stops after login, so it misses the documented Claude
web-flow and the follow-up status redaction check. Update the flow in the auth
claude login test to invoke the web variant of the login command, then call auth
claude status to verify the post-login state instead of relying only on login
output. Keep the existing token persistence checks, and add/assert that status
output does not print the OAuth token or token marker. Use the existing auth
claude login, auth claude status, and OAUTH_TOKEN_MARKER references to locate
the test logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d6cc3051-c82d-4914-9684-6a35457babac

📥 Commits

Reviewing files that changed from the base of the PR and between f601d55 and c114e64.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (40)
  • .changeset/fix-claude-auth-login-probe.md
  • .github/actions/setup/action.yml
  • .github/workflows/check.yml
  • package.json
  • packages/api/Dockerfile
  • packages/app/CHANGELOG.md
  • packages/app/package.json
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/package.json
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/auth-oauth/src/index.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tsconfig.json
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/container/tests/core/templates.test.ts
  • packages/docker-git-session-sync/CHANGELOG.md
  • packages/docker-git-session-sync/package.json
  • packages/lib/package.json
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • pnpm-workspace.yaml
  • scripts/e2e/_lib.sh
  • scripts/e2e/auth-claude-login.sh
  • scripts/e2e/run-all.sh
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
  • GitHub Check: E2E (OpenCode)
  • GitHub Check: E2E (Runtime volumes + SSH)
  • GitHub Check: E2E (Clone auto-open SSH)
  • GitHub Check: E2E (Clone cache)
  • GitHub Check: E2E (Browser command)
  • GitHub Check: E2E (Claude auth login)
  • GitHub Check: E2E (Login context)
  • GitHub Check: Lint
  • GitHub Check: Test
  • GitHub Check: Final build (windows-latest)
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce command injection or unsafe shell/process execution with user-controlled input

Files:

  • packages/auth-oauth/src/index.ts
  • scripts/e2e/run-all.sh
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • scripts/e2e/_lib.sh
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • scripts/e2e/auth-claude-login.sh
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce path traversal or writes outside intended project/container state directories

Files:

  • packages/auth-oauth/src/index.ts
  • scripts/e2e/run-all.sh
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • scripts/e2e/_lib.sh
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • scripts/e2e/auth-claude-login.sh
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output

Files:

  • packages/auth-oauth/src/index.ts
  • pnpm-workspace.yaml
  • packages/auth-oauth/tsconfig.json
  • scripts/e2e/run-all.sh
  • packages/docker-git-session-sync/package.json
  • packages/app/package.json
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • scripts/e2e/_lib.sh
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/package.json
  • package.json
  • packages/auth-oauth/package.json
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • scripts/e2e/auth-claude-login.sh
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: FUNCTIONAL CORE: Write only pure functions with immutable data and mathematical operations in core modules; no side effects, mutations, or external service calls
IMPERATIVE SHELL: Isolate all side effects (IO, network, database, environment/process) in a thin SHELL layer; CORE never calls SHELL, only SHELL → CORE
Never use any type annotation in TypeScript; use unknown only at SHELL boundaries for decoding, never export unknown outside boundary modules
Never use as type assertions in normal code; only permit as in a single 'axiomatic' module (brands, constructors, constants) after which types flow safely without casts
Always use exhaustive pattern matching for union types through .exhaustive() or Match.exhaustive() from effect-ts; never use switch statements or unhandled type branches
Use Effect<Success, Error, Requirements> monad from effect-ts for all effects; compose through pipe() and Effect.flatMap(); never use async/await, raw Promise chains (then/catch), or Promise.all in product code
Interoperate with Promise/exceptions only in SHELL through Effect.try/Effect.tryPromise with typed error mapping; never leave raw exceptions or untyped errors in the domain
Use Effect.acquireRelease + Effect.scoped for resource management with guaranteed finalization; never manage resources with try/finally or manual cleanup
All external services (database, HTTP, environment) must be accessed through Effect-based interfaces and Layer-based dependency injection; never call external APIs directly
Provide comprehensive TSDoc comments with mathematical notation: @pure, @effect, @invariant, @precondition, @postcondition, @complexity, @throws, and CHANGE/WHY/REF/SOURCE/FORMAT THEOREM functional comment markers
No console.*, process direct calls, or untyped environment access in product code; all such operations must be abstracted through Layer-based services in SHELL
Boundary data from external sources (HTTP, database, environment) must be decoded/valida...

Files:

  • packages/auth-oauth/src/index.ts
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/{browser*,server*,app*,*.ts,*.js}

📄 CodeRabbit inference engine (README.md)

Web version must listen on 0.0.0.0 by default for accessibility across LAN devices

Files:

  • packages/auth-oauth/src/index.ts
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/{cli*,command*,auto*,*.ts,*.tsx}

📄 CodeRabbit inference engine (README.md)

Implement auto-mode agent selection logic to choose Claude, Codex, Gemini, or Grok randomly from available authorized providers, or allow forced selection with --auto=

Files:

  • packages/auth-oauth/src/index.ts
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**

⚙️ CodeRabbit configuration file

**: РОЛЬ: Математик-программист, специализирующийся на формально верифицируемой функциональной архитектуре.

ЦЕЛЬ: Создавать математически доказуемые решения через функциональную парадигму с полным разделением чистых вычислений и контролируемых эффектов.

МОДЕЛЬ РАССУЖДЕНИЯ:

  • Не выдавать “личные мнения”. Формировать вывод как результат симуляции профессионального обсуждения релевантных ролей
    (архитектор Effect/FP, ревьюер типов, страж CORE↔SHELL, тест-инженер).
  • Если запрос сформулирован как “что думаешь”, отвечать в терминах аргументов ролей и выбирать решение
    по критериям инвариантов, типовой безопасности и тестируемости (если пользователь явно просит выбор — выбрать и обосновать).

ПРАВИЛО ПРОЦЕССА (НЕ ФОРМАТ ОТВЕТА):
В начале работы (внутренне) формулировать Deep Research вопрос:
"I am looking for code that does , is there existing code that can do this?"
Далее:

  • если доступен проект/код — сперва искать и переиспользовать существующие паттерны (минимальный корректный diff),
  • если проект недоступен — опираться на предоставленный контекст и явно фиксировать допущения,
  • код писать только после формального понимания задачи (типы/инварианты → архитектура → код → тесты),
  • источники указывать только если реально использован внешний материал; иначе SOURCE: n/a.

ИНСТРУМЕНТАЛЬНОЕ ПОВЕДЕНИЕ (ОБЯЗАТЕЛЬНО, НЕ ФОРМАТ ОТВЕТА):

  • Агент всегда использует доступные инструменты среды (терминал, поиск по проекту, запуск тестов/скриптов, анализ сборки, web-ресёрч при необходимости)
    для ресёрча, проверки гипотез и выполнения действий. Приоритет: проверяемость, воспроизводимость, минимальный риск.
  • Агент не предлагает “гайд” как замену действия. Если действие возможно выполнить инструментами — агент выполняет его сам,
    затем сообщает, что было сделано и как повторить.
  • Любые инструкции (команды/процедуры) агент даёт только после собственной проверки на доступной среде.
    Если проверить невозможно — явно фиксирует ограничение и перечисляе...

Files:

  • packages/auth-oauth/src/index.ts
  • pnpm-workspace.yaml
  • packages/auth-oauth/tsconfig.json
  • scripts/e2e/run-all.sh
  • packages/docker-git-session-sync/package.json
  • packages/docker-git-session-sync/CHANGELOG.md
  • packages/app/package.json
  • packages/app/CHANGELOG.md
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • scripts/e2e/_lib.sh
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/package.json
  • package.json
  • packages/auth-oauth/package.json
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • scripts/e2e/auth-claude-login.sh
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/api/Dockerfile
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.

Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.

Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.

Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.

Files:

  • packages/auth-oauth/src/index.ts
  • pnpm-workspace.yaml
  • packages/auth-oauth/tsconfig.json
  • scripts/e2e/run-all.sh
  • packages/docker-git-session-sync/package.json
  • packages/docker-git-session-sync/CHANGELOG.md
  • packages/app/package.json
  • packages/app/CHANGELOG.md
  • packages/container/tests/core/templates.test.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • scripts/e2e/_lib.sh
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/package.json
  • package.json
  • packages/auth-oauth/package.json
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • scripts/e2e/auth-claude-login.sh
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/api/Dockerfile
  • packages/lib/src/usecases/state-repo/lock.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/app/tests/docker-git/controller-compose-fixture.ts
  • packages/auth-oauth/src/claude-local-smoke.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
  • packages/auth-oauth/src/claude-oauth-token.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/container/src/core/templates/dockerfile-prelude.ts
  • packages/app/src/docker-git/controller-compose.ts
  • packages/lib/src/usecases/state-repo.ts
**/{setup,install,config,*.sh,*.md}

📄 CodeRabbit inference engine (README.md)

Ensure default projects directory is ~/.docker-git

Files:

  • scripts/e2e/run-all.sh
  • packages/docker-git-session-sync/CHANGELOG.md
  • packages/app/CHANGELOG.md
  • scripts/e2e/_lib.sh
  • scripts/e2e/auth-claude-login.sh
**/{.git*,config*,*.sh,docker-compose*}

📄 CodeRabbit inference engine (README.md)

Use git credential helper to automatically select correct token by host for HTTPS clone/push operations

Files:

  • scripts/e2e/run-all.sh
  • scripts/e2e/_lib.sh
  • scripts/e2e/auth-claude-login.sh
**/{browser*,server*,.env*,*.sh}

📄 CodeRabbit inference engine (README.md)

Allow DOCKER_GIT_WEB_HOST environment variable to restrict web access to 127.0.0.1

Files:

  • scripts/e2e/run-all.sh
  • scripts/e2e/_lib.sh
  • scripts/e2e/auth-claude-login.sh
**/{package*.json,requirements*.txt,setup.py,setup.cfg,Pipfile,Pipfile.lock,pyproject.toml,pom.xml,build.gradle,Gemfile,Gemfile.lock,go.mod,go.sum,composer.json,Cargo.toml,Cargo.lock}

📄 CodeRabbit inference engine (Custom checks)

Fail if dependency or package-manager changes materially increase supply-chain risk without justification

Files:

  • packages/docker-git-session-sync/package.json
  • packages/app/package.json
  • packages/lib/package.json
  • package.json
  • packages/auth-oauth/package.json
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx}: Write property-based tests using fast-check (fc.property) to verify mathematical invariants; unit tests must use Effect test utilities without async/await
Every bug fix must be accompanied by a reproducing test case; the test must fail before the fix and pass after; document the Proof of Fix with root cause and solution

Files:

  • packages/container/tests/core/templates.test.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • packages/auth-oauth/tests/claude-oauth-token.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/tests/claude-local-smoke.test.ts
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/tests/usecases/state-repo-auto-sync.test.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/app/tests/docker-git/controller-compose.test.ts
**/{.env*,auth*,config*,setup*}

📄 CodeRabbit inference engine (README.md)

Store authentication tokens in env-file as GIT_AUTH_TOKEN__ / GIT_AUTH_USER__

Files:

  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/usecases/auth-claude-local.test.ts
  • packages/lib/src/usecases/auth-claude-login-flow.ts
  • scripts/e2e/auth-claude-login.sh
  • packages/lib/tests/usecases/auth-claude-login-flow.test.ts
  • packages/lib/src/usecases/auth-claude-local.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/lib/src/usecases/auth-claude-oauth.ts
  • packages/lib/src/usecases/auth-claude.ts
**/.github/workflows/*.{yml,yaml}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce unsafe GitHub Actions configuration such as unsafe pull_request_target, or unnecessary write permissions

Files:

  • .github/workflows/check.yml
package.json

📄 CodeRabbit inference engine (AGENTS.md)

Dependencies must include effect ^3.x and @effect/schema ^0.x; prohibit downgrading these versions or introducing incompatible alternatives (async-only libraries without Effect support)

Require Effect and @effect/schema as mandatory dependencies for type-safe effects and validation

Files:

  • package.json
**/{Dockerfile*,docker-compose*.{yml,yaml},.dockerignore}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce unsafe Docker configuration such as privileged containers, broad host mounts, unbounded Docker socket access, or unnecessary write permissions

Files:

  • packages/api/Dockerfile
🧠 Learnings (2)
📚 Learning: 2026-05-22T21:08:18.083Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 344
File: packages/app/src/docker-git/controller-compose.ts:34-40
Timestamp: 2026-05-22T21:08:18.083Z
Learning: In this repo’s docker-git controller compose generation, `${DOCKER_GIT_CONTROLLER_BUILD_SKILLER:-1}` should be treated as standard bash parameter expansion: when `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` is unset, it defaults to the string "1". There is no "-1" mode. The runtime contract enforced by `packages/app/src/docker-git/controller-compose.ts` is: unset / "1" / "true" => output "1"; "0" / "false" => output "0". If review code shows branching/behavior for "-1" or any numeric value other than this 0/1 contract, flag it. Also ensure the Dockerfile ARG `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` stays consistent with default `1`.

Applied to files:

  • packages/app/src/docker-git/controller-compose-files.ts
  • packages/app/src/docker-git/controller-compose.ts
📚 Learning: 2026-06-10T10:21:51.286Z
Learnt from: konard
Repo: ProverCoderAI/docker-git PR: 386
File: packages/app/tests/docker-git/gridland-react-singleton.test.ts:0-0
Timestamp: 2026-06-10T10:21:51.286Z
Learning: In `packages/app/tests/docker-git` tests that inspect the `packages/terminal` workspace (e.g., for React-related versions), remember that `react-dom` is intentionally declared as a `devDependency` in `packages/terminal` (the terminal exports components but does not render to the DOM itself). Therefore, test assertions should not require `react-dom` to appear in `dependencies`; when resolving versions, accept either `dependencies` or `devDependencies` (as `resolveDepVersion` does in `gridland-react-singleton.test.ts`).

Applied to files:

  • packages/app/tests/docker-git/controller-compose.test.ts
🪛 ast-grep (0.44.0)
scripts/e2e/auth-claude-login.sh

[warning] 116-116: set +e (or set +o errexit) disables the shell's errexit option, so the script keeps running after a command fails. This masks failures of security-critical operations (downloads, signature/checksum verification, permission changes, cleanup of secrets), letting the script proceed with a bad or insecure state. Leave errexit enabled (set -e / set -euo pipefail), or handle failures explicitly with if/|| and an explicit exit instead of globally turning off failure detection.
Context: set +e
Note: [CWE-754] Improper Check for Unusual or Exceptional Conditions.

(set-plus-e-error-masking-bash)


[warning] 17-17: A credential-bearing variable (e.g. PASSWORD, PASSWD, SECRET, TOKEN, API_KEY) is assigned a hardcoded string literal. Secrets committed to a script are exposed in source control, process listings, and shell history, and cannot be rotated without a code change. Read the value from a secrets manager or an injected environment variable at runtime instead (e.g. PASSWORD="${DB_PASSWORD:?must be set}"), and never commit the literal.
Context: OAUTH_TOKEN_MARKER="sk-ant-oat01-docker-git-e2e-oauth-token-marker"
Note: [CWE-798] Use of Hard-coded Credentials.

(hardcoded-password-assignment-bash)

packages/auth-oauth/src/claude-docker-oauth.ts

[warning] 4-4: Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process"
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

packages/auth-oauth/src/claude-local-smoke.ts

[warning] 4-4: Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process"
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🪛 Checkov (3.3.2)
packages/auth-oauth/package.json

[low] 15-16: Base64 High Entropy String

(CKV_SECRET_6)

🪛 Hadolint (2.14.0)
packages/api/Dockerfile

[info] 120-120: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)


[info] 121-121: Multiple consecutive RUN instructions. Consider consolidation.

(DL3059)

🪛 markdownlint-cli2 (0.22.1)
.changeset/fix-claude-auth-login-probe.md

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🪛 OpenGrep (1.23.0)
packages/auth-oauth/src/claude-oauth-token.ts

[ERROR] 204-204: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 209-209: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🪛 Shellcheck (0.11.0)
scripts/e2e/auth-claude-login.sh

[info] 118-118: Expressions don't expand in single quotes, use double quotes for that.

(SC2016)

🔇 Additional comments (10)
packages/app/CHANGELOG.md (1)

3-10: LGTM!

packages/app/package.json (1)

3-3: LGTM!

packages/docker-git-session-sync/CHANGELOG.md (1)

3-7: LGTM!

packages/docker-git-session-sync/package.json (1)

3-3: LGTM!

.github/workflows/check.yml (1)

252-271: LGTM!

scripts/e2e/run-all.sh (1)

8-8: LGTM!

scripts/e2e/_lib.sh (1)

21-47: LGTM!

packages/container/src/core/templates/dockerfile-prelude.ts (1)

87-87: LGTM!

Also applies to: 97-101

packages/container/tests/core/templates.test.ts (1)

211-211: LGTM!

packages/auth-oauth/package.json (1)

34-41: 📐 Maintainability & Code Quality

Не переносить effect в runtime dependencies

packages/auth-oauth/src/* не импортирует ни effect, ни @effect/schema; эти зависимости используются только в тестах. Для этого пакета devDependencies достаточно, а @effect/schema здесь не требуется.

			> Likely an incorrect or invalid review comment.

Comment on lines +61 to +88
run_bun_install() {
local timeout_seconds=$((20 * 60))
bun install --frozen-lockfile &
local install_pid="$!"
(
sleep "$timeout_seconds"
echo "bun install exceeded 20 minutes; terminating" >&2
kill "$install_pid" 2>/dev/null || true
) &
local timeout_pid="$!"
local status=0
wait "$install_pid" || status="$?"
kill "$timeout_pid" 2>/dev/null || true
wait "$timeout_pid" 2>/dev/null || true
return "$status"
}

for attempt in 1 2 3; do
if run_bun_install; then
exit 0
fi
if [[ "$attempt" == "3" ]]; then
echo "bun install failed after retries" >&2
exit 1
fi
echo "bun install attempt ${attempt} failed; retrying..." >&2
sleep $((attempt * 2))
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Ретраи здесь недостижимы в текущем workflow timeout.

На Line 62 одна попытка может ждать 20 минут, но .github/workflows/check.yml уже использует этот action в build job с timeout-minutes: 10. В этом job GitHub завершит весь job раньше первого watchdog/retry, так что новая логика не даст заявленного восстановления после transient install failures. Сведите watchdog ниже минимального job timeout или поднимите timeout job.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/setup/action.yml around lines 61 - 88, The retry logic in
run_bun_install is effectively unreachable because the surrounding build job can
time out before the first 20-minute watchdog finishes. Update the action’s
timeout handling so it fits within the job’s actual timeout in the check
workflow, either by reducing the bun install watchdog/retry window or by
aligning the job timeout higher; keep the fix centered around run_bun_install
and the retry loop in this action.

Comment on lines +63 to +74
bun install --frozen-lockfile &
local install_pid="$!"
(
sleep "$timeout_seconds"
echo "bun install exceeded 20 minutes; terminating" >&2
kill "$install_pid" 2>/dev/null || true
) &
local timeout_pid="$!"
local status=0
wait "$install_pid" || status="$?"
kill "$timeout_pid" 2>/dev/null || true
wait "$timeout_pid" 2>/dev/null || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

На timeout нужно завершать всю process group, а не только родительский PID.

На Lines 63-74 watchdog шлёт kill только в bun install. Если postinstall или другой lifecycle-скрипт породит дочерние процессы, они переживут retry и смогут оставить lock/сокеты/IO, а следующая попытка стартует поверх них. Здесь нужен запуск в отдельной process group и сигнал по всей группе.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/setup/action.yml around lines 63 - 74, Update the timeout
handling in the setup action so the watchdog kills the entire process group, not
just the `bun install` parent PID. In the `bun install --frozen-lockfile` block,
start the install in its own process group and make the timeout path send the
termination signal to that group, including any child processes spawned by
lifecycle scripts. Keep the existing `install_pid`, `timeout_pid`, and `wait`
flow in the action, but change the termination logic to target the full group.

Comment on lines +20 to +21
const mapComposePathError = (error: PlatformError): ControllerBootstrapError =>
controllerBootstrapError(`Failed to resolve docker-compose.yml path.\nDetails: ${String(error)}`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Сообщение об ошибке здесь стало вводить в заблуждение.

mapComposePathError() теперь используется не только для базового docker-compose.yml, но и для extra/GPU overlay-путей. Если exists/stat упадёт на overlay-файле, пользователь всё равно увидит “Failed to resolve docker-compose.yml path”, хотя сломан уже другой вход. Лучше передавать контекст в mapper или разделить mapper'ы по типу overlay.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/src/docker-git/controller-compose-files.ts` around lines 20 -
21, The error text in mapComposePathError is too specific to docker-compose.yml,
but this mapper is also used for extra and GPU overlay paths. Update the error
mapping in controller-compose-files so the message includes the actual
path/context being resolved, or split the mapper into separate helpers for base
and overlay resolution; make sure callers from the compose path resolution flow
pass the relevant overlay name or file type into the mapper.

Comment on lines +246 to +248
const extraOverlayPath = yield* _(loadControllerComposeExtraPath())
const runtimeOverlayPath = yield* _(resolveControllerRuntimeOverlayPath(composePath, dockerRuntime))
return { ...composeFiles, runtimeOverlayPath }
return { ...composeFiles, extraOverlayPath, runtimeOverlayPath }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Проверка regular-file всё ещё не покрывает isolated runtime overlay.

resolveControllerComposeFiles() теперь валидирует extra/GPU overlays, но resolveControllerRuntimeOverlayPath() по-прежнему принимает любой существующий путь. Если docker-compose.isolated.yml окажется директорией, этот путь всё равно дойдёт до docker compose -f ... и свалится уже после bootstrap — ровно тот класс ошибки, который этот PR устраняет для остальных overlay-файлов. Добавьте ту же stat(...).type === "File" проверку для runtime overlay и отдельный регрессионный тест.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/src/docker-git/controller-compose.ts` around lines 246 - 248,
The runtime overlay path in resolveControllerRuntimeOverlayPath() still accepts
any existing path, so add the same stat(...).type === "File" validation used for
the other overlays to reject directories for docker-compose.isolated.yml as
well. Update the runtime overlay resolution flow in controller-compose.ts to
fail early with a clear error before docker compose is invoked, and add a
regression test covering a directory passed as the isolated runtime overlay.

Comment on lines +119 to +128
const controllerBuildSkillerFixtureModeArbitrary = fc.constantFrom<ControllerBuildSkillerFixtureMode>(
undefined,
"0",
"1"
)
export const controllerDockerRuntimeEnvFixtureModeArbitrary = fc.constantFrom<ControllerDockerRuntimeEnvFixtureMode>(
undefined,
"host",
"isolated"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Арбитрар не покрывает полный контракт DOCKER_GIT_CONTROLLER_BUILD_SKILLER.

Сейчас fixture генерирует только undefined | "0" | "1", поэтому ветки "true" и "false" больше не проверяются, хотя парсер режима должен принимать их как алиасы "1" и "0". Добавьте эти значения в controllerBuildSkillerFixtureModeArbitrary, иначе регрессия в нормализации env останется незамеченной. Based on learnings, поддерживаемый контракт здесь — unset / "1" / "true""1" и "0" / "false""0".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/tests/docker-git/controller-compose-fixture.ts` around lines 119
- 128, The controller build skiller fixture arbitrary does not cover the full
DOCKER_GIT_CONTROLLER_BUILD_SKILLER contract, so add the missing alias values to
controllerBuildSkillerFixtureModeArbitrary in controller-compose-fixture.ts.
Update the fc.constantFrom set to include "true" and "false" alongside
undefined, "0", and "1", so the parser normalization path for env aliases is
exercised and regressions in the build-skiller mode handling are caught.

Source: Learnings

Comment on lines +20 to +45
const acquireStateFileLock = (
fs: FileSystem.FileSystem,
lockPath: string,
attempt: number = 0
): Effect.Effect<string, CommandFailedError | PlatformError> =>
fs.makeDirectory(lockPath).pipe(
Effect.as(lockPath),
Effect.catchTag("SystemError", (error) => {
if (!isStateFileLockBusy(error)) {
return Effect.fail(error)
}
if (attempt >= stateGitLockMaxAttempts) {
return Effect.fail(new CommandFailedError({ command: "state git lock", exitCode: stateGitLockBusyExitCode }))
}
return Effect.sleep(stateGitLockRetryDelay).pipe(
Effect.zipRight(acquireStateFileLock(fs, lockPath, attempt + 1))
)
})
)

const releaseStateFileLock = (
fs: FileSystem.FileSystem,
lockPath: string
): Effect.Effect<void> =>
fs.remove(lockPath, { recursive: true, force: true }).pipe(
Effect.orElseSucceed(() => void 0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Каталоговый lock может застрять навсегда после crash.

На Line 25 создаётся постоянный <root>.lock, а на Lines 40-45 он снимается только в release-path. Если процесс/контейнер завершится между acquire и release, каталог останется на диске без owner/ttl, и все следующие withStateGitLock будут лишь ретраить 5 секунд и падать. Это превращает единичный crash в бессрочный отказ autoSyncState/autoPullState, пока кто-то вручную не удалит lock. Нужен reclaim stale lock (например, owner metadata + age/liveness check) или системный file lock.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/state-repo/lock.ts` around lines 20 - 45, The state
lock in acquireStateFileLock/releaseStateFileLock can remain forever if the
process crashes before cleanup, because the <root>.lock directory has no owner
or expiry handling. Update the lock flow in acquireStateFileLock and the
withStateGitLock path to detect and reclaim stale locks, for example by storing
owner/heartbeat metadata and checking age or liveness before treating the lock
as busy, or by switching to a real system file lock. Keep releaseStateFileLock
as best-effort cleanup, but make lock acquisition resilient to orphaned lock
directories.

Comment on lines +75 to +79
Effect.gen(function*(_) {
const fs = yield* _(FileSystem.FileSystem)
const path = yield* _(Path.Path)
const root = resolveStateRoot(path, process.cwd())
const lockPath = resolveStateLockPath(root)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Уберите прямой process.cwd() из продукт-кода.

На Line 78 ключ блокировки зависит от глобального состояния процесса, хотя этот слой уже живёт в Effect runtime и может получать cwd/root через service или явный параметр. Так код останется тестируемым и будет соответствовать границе SHELL. As per coding guidelines, "No console.*, process direct calls, or untyped environment access in product code; all such operations must be abstracted through Layer-based services in SHELL".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/state-repo/lock.ts` around lines 75 - 79, The lock
repository logic currently reads cwd directly via process.cwd(), which should be
removed from product code. Update the state lock flow in lock.ts, especially the
Effect.gen block that calls resolveStateRoot, to obtain cwd/root through an
Effect service or an explicit parameter instead of the global process. Keep
resolveStateLockPath and the surrounding repository logic unchanged, but wire
the cwd source through the existing Effect runtime boundary so the code remains
testable and SHELL-compliant.

Source: Coding guidelines

Comment on lines +93 to +96
it.effect("normalizes token whitespace at the flow boundary", () =>
Effect.sync(() => {
expect(normalizeClaudeOauthToken(`\n${oauthToken}\n`)).toBe(oauthToken)
}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Этот тест обходит сам flow и не доказывает boundary-нормализацию.

Сейчас проверяется только normalizeClaudeOauthToken(), поэтому регресс в runClaudeLoginFlow() на Line 69 (например, если убрать ensureClaudeOauthToken) этот кейс не поймает. Для proof-of-fix здесь нужен flow-level тест: передать captureToken с обрамляющими пробелами/переводами строки и проверить, что в persistToken и probeToken приходит уже trim-значение. As per coding guidelines, "*.test.ts" должны проверять инварианты через fc.property, и "Every bug fix must be accompanied by a reproducing test case...".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/tests/usecases/auth-claude-login-flow.test.ts` around lines 93 -
96, The current test only covers normalizeClaudeOauthToken directly and bypasses
runClaudeLoginFlow, so it will miss regressions in the boundary handling. Update
the test in auth-claude-login-flow.test.ts to exercise runClaudeLoginFlow with a
captureToken containing surrounding whitespace/newlines, and assert that
persistToken and probeToken receive the trimmed token value. Keep the check at
the flow boundary using the runClaudeLoginFlow/ensureClaudeOauthToken path
rather than testing normalizeClaudeOauthToken in isolation, and follow the test
style conventions by expressing the invariant with fc.property where
appropriate.

Source: Coding guidelines

Comment on lines +102 to +179
describe("state repo auto sync", () => {
it.effect("skips non-strict auto-sync before git add when the git index is locked", () =>
withTempDir((home) =>
withPatchedEnv(
{
HOME: home,
DOCKER_GIT_PROJECTS_ROOT: undefined,
DOCKER_GIT_STATE_AUTO_SYNC: "1",
DOCKER_GIT_STATE_AUTO_SYNC_STRICT: undefined
},
Effect.gen(function*(_) {
const fs = yield* _(FileSystem.FileSystem)
const path = yield* _(Path.Path)
const root = path.join(home, ".docker-git")
const indexLockPath = path.join(root, ".git", "index.lock")
const recorded: Array<RecordedCommand> = []
const logs: Array<string> = []
const logger = Logger.make(({ message }) => {
logs.push(String(message))
})

yield* _(fs.makeDirectory(path.join(root, ".git"), { recursive: true }))
yield* _(fs.writeFileString(indexLockPath, "locked\n"))

yield* _(
autoSyncState("chore(state): test").pipe(
Effect.provideService(CommandExecutor.CommandExecutor, makeFakeExecutor(recorded)),
Effect.provide(Logger.replace(Logger.defaultLogger, logger))
)
)

expect(recorded.filter(isMutatingSyncGitCommand)).toEqual([])
expect(logs.some((message) => message.includes("State auto-sync skipped: git index lock exists"))).toBe(true)
expect(yield* _(fs.exists(`${root}.lock`))).toBe(false)
})
)
).pipe(Effect.provide(NodeContext.layer)))

it.effect("releases the state lock when non-strict auto-sync logs a git failure", () =>
withTempDir((home) =>
withPatchedEnv(
{
HOME: home,
DOCKER_GIT_PROJECTS_ROOT: undefined,
DOCKER_GIT_STATE_AUTO_SYNC: "1",
DOCKER_GIT_STATE_AUTO_SYNC_STRICT: undefined
},
Effect.gen(function*(_) {
const fs = yield* _(FileSystem.FileSystem)
const path = yield* _(Path.Path)
const root = path.join(home, ".docker-git")
const recorded: Array<RecordedCommand> = []
const logs: Array<string> = []
const logger = Logger.make(({ message }) => {
logs.push(String(message))
})

yield* _(fs.makeDirectory(path.join(root, ".git"), { recursive: true }))

yield* _(
autoSyncState("chore(state): test").pipe(
Effect.provideService(
CommandExecutor.CommandExecutor,
makeFakeExecutor(recorded, (command) =>
command.command === "git" && command.args[0] === "rm" ? 23 : 0
)
),
Effect.provide(Logger.replace(Logger.defaultLogger, logger))
)
)

expect(recorded.some((command) => command.command === "git" && command.args[0] === "rm")).toBe(true)
expect(logs.some((message) => message.includes("State auto-sync failed: git rm (exit 23)"))).toBe(true)
expect(yield* _(fs.exists(`${root}.lock`))).toBe(false)
})
)
).pipe(Effect.provide(NodeContext.layer)))
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect repository test patterns and the target file context.
git ls-files | sed -n '1,200p'
printf '\n--- target file ---\n'
cat -n packages/lib/tests/usecases/state-repo-auto-sync.test.ts | sed -n '1,260p'
printf '\n--- search for fast-check usage in tests ---\n'
rg -n --glob '*.test.ts' --glob '*.test.tsx' 'fc\.property|fast-check|property-based' packages | sed -n '1,240p'
printf '\n--- search for this specific behavior elsewhere ---\n'
rg -n 'State auto-sync skipped: git index lock exists|State auto-sync failed: git rm \(exit 23\)|index\.lock|state auto-sync' packages | sed -n '1,240p'

Repository: ProverCoderAI/docker-git

Length of output: 36931


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Focus on nearby code if the file is long.
wc -l packages/lib/tests/usecases/state-repo-auto-sync.test.ts
sed -n '1,220p' packages/lib/tests/usecases/state-repo-auto-sync.test.ts

Repository: ProverCoderAI/docker-git

Length of output: 6973


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read surrounding test conventions if the target file alone is insufficient.
fd -a 'docs' . || true
rg -n --glob 'docs/**/*.md' --glob '*.md' 'fast-check|fc\.property|property-based|bug fix|reproducing test' . | sed -n '1,240p'

Repository: ProverCoderAI/docker-git

Length of output: 802


Добавь property-based покрытие инвариантов auto-sync
packages/lib/tests/usecases/state-repo-auto-sync.test.ts:102-179 — сейчас здесь только два фиксированных сценария; добавь fc.property, который варьирует наличие index.lock и коды выхода git-команд, чтобы закрепить index.lock ⇒ mutating git commands = 0 и git failure ⇒ .lock отсутствует.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/tests/usecases/state-repo-auto-sync.test.ts` around lines 102 -
179, Current tests only cover two fixed auto-sync cases; add a property-based
test around autoSyncState to vary whether .git/index.lock exists and the git
exit codes. Use fc.property with the existing helpers like withTempDir,
withPatchedEnv, makeFakeExecutor, and isMutatingSyncGitCommand to assert the
invariants that index.lock implies zero mutating git commands and that any git
failure still leaves the state .lock file absent. Keep the existing logging
assertions where relevant, but move the core expectations into the generated
property cases so the behavior is checked across many combinations.

Source: Coding guidelines

Comment on lines +117 to +142
set +e
timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude login' bash "$REPO_ROOT" \
>"$LOG_FILE" 2>&1
login_exit=$?
set -e

if [[ "$login_exit" -ne 0 ]]; then
cat "$LOG_FILE" >&2 || true
fail "docker-git auth claude login failed (exit: $login_exit)"
fi

if grep -Fq -- "$OAUTH_TOKEN_MARKER" "$LOG_FILE"; then
fail "expected OAuth token marker to be absent from auth claude login output"
fi

grep -Fq -- "Claude OAuth token saved" "$LOG_FILE" \
|| fail "expected saved-token warning in auth claude login output"

grep -Fq -- "live Claude API access is not yet verified" "$LOG_FILE" \
|| fail "expected diagnostic API probe warning in auth claude login output"

docker exec "$DOCKER_GIT_API_CONTAINER_NAME" \
test -s "$ROOT/.orch/auth/claude/default/.oauth-token" \
|| fail "expected persisted Claude OAuth token in controller state"

echo "e2e/auth-claude-login: docker-backed Claude login warning path verified" >&2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Покройте документированный web-flow и повторную проверку через status.

Сейчас e2e запускает auth claude login без --web и на этом останавливается, поэтому не проверяет контракт из README: web-вход должен идти через auth claude login --web, а состояние после warning нужно перепроверять auth claude status с проверкой, что токен не попадает в вывод. В текущем виде регрессия в CLI-маршрутизации --web или в redaction/status останется незамеченной.

🧪 Предлагаемый фикс
 set +e
-timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude login' bash "$REPO_ROOT" \
+timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude login --web' bash "$REPO_ROOT" \
   >"$LOG_FILE" 2>&1
 login_exit=$?
 set -e
@@
 grep -Fq -- "live Claude API access is not yet verified" "$LOG_FILE" \
   || fail "expected diagnostic API probe warning in auth claude login output"
+
+STATUS_LOG_FILE="/tmp/docker-git-auth-claude-status-$RUN_ID.log"
+
+set +e
+timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude status' bash "$REPO_ROOT" \
+  >"$STATUS_LOG_FILE" 2>&1
+status_exit=$?
+set -e
+
+if [[ "$status_exit" -ne 0 ]]; then
+  cat "$STATUS_LOG_FILE" >&2 || true
+  fail "docker-git auth claude status failed (exit: $status_exit)"
+fi
+
+if grep -Fq -- "$OAUTH_TOKEN_MARKER" "$STATUS_LOG_FILE"; then
+  fail "expected OAuth token marker to be absent from auth claude status output"
+fi

As per path instructions, "follow the documented CLI usage: bun run docker-git auth claude login --web (web flow) and use docker-git auth claude status to re-check issues instead of expecting the login command to fail hard on transient probe problems. Also ensure any test/log assertions align with the documented guarantee that status does not print token values."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
set +e
timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude login' bash "$REPO_ROOT" \
>"$LOG_FILE" 2>&1
login_exit=$?
set -e
if [[ "$login_exit" -ne 0 ]]; then
cat "$LOG_FILE" >&2 || true
fail "docker-git auth claude login failed (exit: $login_exit)"
fi
if grep -Fq -- "$OAUTH_TOKEN_MARKER" "$LOG_FILE"; then
fail "expected OAuth token marker to be absent from auth claude login output"
fi
grep -Fq -- "Claude OAuth token saved" "$LOG_FILE" \
|| fail "expected saved-token warning in auth claude login output"
grep -Fq -- "live Claude API access is not yet verified" "$LOG_FILE" \
|| fail "expected diagnostic API probe warning in auth claude login output"
docker exec "$DOCKER_GIT_API_CONTAINER_NAME" \
test -s "$ROOT/.orch/auth/claude/default/.oauth-token" \
|| fail "expected persisted Claude OAuth token in controller state"
echo "e2e/auth-claude-login: docker-backed Claude login warning path verified" >&2
set +e
timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude login --web' bash "$REPO_ROOT" \
>"$LOG_FILE" 2>&1
login_exit=$?
set -e
if [[ "$login_exit" -ne 0 ]]; then
cat "$LOG_FILE" >&2 || true
fail "docker-git auth claude login failed (exit: $login_exit)"
fi
if grep -Fq -- "$OAUTH_TOKEN_MARKER" "$LOG_FILE"; then
fail "expected OAuth token marker to be absent from auth claude login output"
fi
grep -Fq -- "Claude OAuth token saved" "$LOG_FILE" \
|| fail "expected saved-token warning in auth claude login output"
grep -Fq -- "live Claude API access is not yet verified" "$LOG_FILE" \
|| fail "expected diagnostic API probe warning in auth claude login output"
STATUS_LOG_FILE="/tmp/docker-git-auth-claude-status-$RUN_ID.log"
set +e
timeout "${LOGIN_TIMEOUT_SECONDS}s" bash -lc 'cd "$1" && bun packages/app/dist/src/docker-git/main.js auth claude status' bash "$REPO_ROOT" \
>"$STATUS_LOG_FILE" 2>&1
status_exit=$?
set -e
if [[ "$status_exit" -ne 0 ]]; then
cat "$STATUS_LOG_FILE" >&2 || true
fail "docker-git auth claude status failed (exit: $status_exit)"
fi
if grep -Fq -- "$OAUTH_TOKEN_MARKER" "$STATUS_LOG_FILE"; then
fail "expected OAuth token marker to be absent from auth claude status output"
fi
docker exec "$DOCKER_GIT_API_CONTAINER_NAME" \
test -s "$ROOT/.orch/auth/claude/default/.oauth-token" \
|| fail "expected persisted Claude OAuth token in controller state"
echo "e2e/auth-claude-login: docker-backed Claude login warning path verified" >&2
🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 118-118: Expressions don't expand in single quotes, use double quotes for that.

(SC2016)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/e2e/auth-claude-login.sh` around lines 117 - 142, The e2e in
auth-claude-login.sh currently exercises the non-web login path and stops after
login, so it misses the documented Claude web-flow and the follow-up status
redaction check. Update the flow in the auth claude login test to invoke the web
variant of the login command, then call auth claude status to verify the
post-login state instead of relying only on login output. Keep the existing
token persistence checks, and add/assert that status output does not print the
OAuth token or token marker. Use the existing auth claude login, auth claude
status, and OAUTH_TOKEN_MARKER references to locate the test logic.

Source: Path instructions

Proof of fix:\n- Причина: AuthClaudeStatus парсился, но host API mode считал его unsupported и не имел /auth/claude/status endpoint.\n- Решение: добавлен controller/API status endpoint, app routing/client dispatch и OpenAPI контракт; статус читает controller state без запуска Claude CLI и без утечки секретов.\n- Доказательство: bun run --cwd packages/api test -- auth.test.ts openapi.test.ts; bun run --cwd packages/app test -- program-auth.test.ts parser-auth.test.ts; typecheck packages api/app/openapi.
@skulidropek

skulidropek commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

AI Session Backup

Commit: 0d8a463
Status: success
Files: 5 (4.73 MB)
Links: README | Manifest

git status

On branch pr-440
Your branch is up to date with 'origin/pr-440'.

nothing to commit, working tree clean

@skulidropek

skulidropek commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

AI Session Backup

Commit: 0d8a463
Status: success
Files: 5 (4.78 MB)
Links: README | Manifest

git status

On branch pr-440
Your branch is up to date with 'origin/pr-440'.

nothing to commit, working tree clean

@skulidropek

Copy link
Copy Markdown
Member Author

Старая инфа: #440

Expose a nullable Claude account field in the controller status response and render it in the status message when safe identity metadata is available.

Proof of fix:

- Cause: Claude status reported only label/method, so a connected account could not be identified like Codex status.

- Solution: read non-secret account metadata from persisted Claude config/credentials, keep token bytes out of the response, and update OpenAPI/contracts/tests.

- Verification: bun run --cwd packages/api test -- auth.test.ts openapi.test.ts; bun run --cwd packages/app test -- program-auth.test.ts parser-auth.test.ts; bun run --cwd packages/lib lint.
@skulidropek

skulidropek commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

AI Session Backup

Commit: ae12482
Status: success
Files: 6 (6.52 MB)
Links: README | Manifest

git status

On branch pr-440
Your branch is up to date with 'origin/pr-440'.

nothing to commit, working tree clean

@skulidropek

skulidropek commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

AI Session Backup

Commit: ae12482
Status: failure
Error: failed to update backup ref: gh: Reference cannot be updated (HTTP 422)

git status

On branch pr-440
Your branch is up to date with 'origin/pr-440'.

nothing to commit, working tree clean

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/lib/src/usecases/state-repo.ts (1)

159-159: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Используйте sanitized failure logger здесь тоже.

Line 159 снова пишет String(error), обходя новый renderStateSyncFailure; так в warning могут попасть абсолютные paths или command context. Замените на общий helper.

Минимальный фикс
-      onFailure: (error) => Effect.logWarning(`State auto-sync failed: ${String(error)}`),
+      onFailure: logStateAutoSyncFailure,

As per coding guidelines, "Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/state-repo.ts` at line 159, The warning in the
state auto-sync failure path is still formatting the raw error with
String(error), which can leak sensitive details. Update the onFailure handler in
state-repo to use the shared sanitized helper renderStateSyncFailure instead of
logging the raw error, so the State auto-sync failed message is consistent and
safe.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/api/src/http.ts`:
- Around line 1142-1150: The `/auth/claude/status` handler currently exposes
auth status without a guard, and `readClaudeAuthStatus()` can leak
`emailAddress`/`displayName` from local credentials. Protect this route with the
same auth check used for other sensitive `/auth/*` endpoints in
`HttpRouter.get`, or remove `account` fields from the payload returned via
`jsonResponse`. Use `readClaudeAuthStatus` and the existing route registration
in `packages/api/src/http.ts` to keep the fix localized.

In `@packages/api/src/services/auth.ts`:
- Around line 565-583: `resolveClaudeAuthMethod` in
`packages/api/src/services/auth.ts` duplicates the Claude auth detection logic
already present in `packages/lib/src/usecases/auth-claude-credentials.ts`, so
the source of truth is split. Extract a shared pure detector (for example,
`detectClaudeAuthMethod(fs, accountPath)`) in the lib usecase and have both the
API-side `resolveClaudeAuthMethod` and the existing lib
`resolveClaudeAuthMethod` call it, keeping the side-effectful sync/clear
behavior only in the lib wrapper.

In `@packages/api/tests/auth.test.ts`:
- Line 22: Add property-based coverage for readClaudeAuthStatus using
fast-check, since the current tests only cover fixed branches and serialization.
Extend the auth.test.ts suite with fc.property-based tests around the
readClaudeAuthStatus flow to validate invariants like connected matching method
!== "none" and label normalization being idempotent. Use the existing
readClaudeAuthStatus test setup and keep the new properties focused on the
returned status shape so they complement the current branch tests without
duplicating them.

In `@packages/app/tests/docker-git/program-auth.test.ts`:
- Around line 1-15: The new program auth test is using plain vitest `it` instead
of the required Effect test utilities. Update `program-auth.test.ts` to follow
the same pattern as `parser-auth.test.ts` by using `it.effect` with
`Effect.sync` (and the matching Effect imports) around the `isRoutedAuthCommand`
assertion, while keeping the test synchronous and free of async/await.

In `@packages/auth-oauth/src/claude-docker-oauth.ts`:
- Line 21: The claudeDockerOauthProbeConfigDir constant currently points to a
root-level path that may not be writable for non-root Docker runs, causing the
probe to fail when Claude tries to create HOME or CLAUDE_CONFIG_DIR. Update
claudeDockerOauthProbeConfigDir in claude-docker-oauth.ts to use a writable
location such as a /tmp-based directory, or ensure the directory is created and
owned appropriately before the probe runs in the claudeDockerOauth flow.

In `@packages/lib/src/usecases/auth-claude-credentials.ts`:
- Around line 58-95: The naming of resolveClaudeAuthMethod is misleading because
it performs filesystem side effects via syncClaudeCredentialsFile and
clearClaudeSessionCredentials instead of only resolving state. Rename the
function to reflect the normalize-and-resolve behavior, and add functional
comments marking syncClaudeCredentialsFile, clearClaudeSessionCredentials, and
the renamed resolver as PURITY: SHELL with a short EFFECT/invariant note,
consistent with persistClaudeOauthToken. Keep the behavior unchanged; just make
the side effects explicit in the symbol names and comments.
- Around line 96-124: `hasNonEmptyOauthToken` duplicates the same token lookup
and normalization logic already implemented in `readOauthToken`. Refactor
`hasNonEmptyOauthToken` to delegate to `readOauthToken(fs, accountPath)` and
return a boolean based on whether it yields a non-null value, keeping the
filesystem/file checks and trimming behavior centralized in `readOauthToken`.

In `@packages/lib/src/usecases/auth-claude.ts`:
- Line 49: The hardcoded claudeProbeConfigDir in auth-claude.ts should not point
to a top-level path that may be unwritable for non-root Docker runs. Update the
probe config directory setup to match claude-docker-oauth.ts by using a writable
/tmp-based location or by explicitly creating and preparing the directory with
the right ownership/permissions before login/status probes use it.

In `@packages/lib/src/usecases/state-repo/init.ts`:
- Line 114: The init usecase is reading the current working directory directly
via process.cwd(), which should be removed from Effect orchestration. Update the
init flow around resolveStateRoot so cwd is injected from the shell boundary or
an environment service passed into the usecase, and use that value instead of
calling process.cwd() inside product code. Keep the dependency explicit through
the existing init/usecase entrypoint and related service boundary so the logic
remains testable and Layer-based.
- Around line 122-123: The logging in the state repo initialization leaks
sensitive information by printing the absolute state directory and the raw
remote URL. Update the logging around the init flow in the state-repo usecase
(the Effect.log calls in init) to use a non-identifying alias for the state
location and a redacted remote string that removes credentials/userinfo from
input.repoUrl. Keep the log context useful, but avoid exposing root or any
embedded tokens in the remote output.

---

Outside diff comments:
In `@packages/lib/src/usecases/state-repo.ts`:
- Line 159: The warning in the state auto-sync failure path is still formatting
the raw error with String(error), which can leak sensitive details. Update the
onFailure handler in state-repo to use the shared sanitized helper
renderStateSyncFailure instead of logging the raw error, so the State auto-sync
failed message is consistent and safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8dfd9eba-02ec-45c2-b4cd-5cf7cfdd8c43

📥 Commits

Reviewing files that changed from the base of the PR and between c114e64 and ae12482.

📒 Files selected for processing (21)
  • packages/api/src/api/contracts.ts
  • packages/api/src/api/openapi.ts
  • packages/api/src/http.ts
  • packages/api/src/services/auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/api-client.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/app/src/docker-git/program-unsupported.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/lib/src/usecases/auth-claude.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/openapi/openapi.json
  • packages/openapi/src/openapi-paths.ts
💤 Files with no reviewable changes (1)
  • packages/app/src/docker-git/program-unsupported.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (10)
  • GitHub Check: Lint
  • GitHub Check: E2E (Browser command)
  • GitHub Check: E2E (Login context)
  • GitHub Check: E2E (Claude auth login)
  • GitHub Check: E2E (Clone auto-open SSH)
  • GitHub Check: E2E (OpenCode)
  • GitHub Check: E2E (Clone cache)
  • GitHub Check: E2E (Runtime volumes + SSH)
  • GitHub Check: Test
  • GitHub Check: Final build (windows-latest)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce command injection or unsafe shell/process execution with user-controlled input

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce path traversal or writes outside intended project/container state directories

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/openapi/openapi.json
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: FUNCTIONAL CORE: Write only pure functions with immutable data and mathematical operations in core modules; no side effects, mutations, or external service calls
IMPERATIVE SHELL: Isolate all side effects (IO, network, database, environment/process) in a thin SHELL layer; CORE never calls SHELL, only SHELL → CORE
Never use any type annotation in TypeScript; use unknown only at SHELL boundaries for decoding, never export unknown outside boundary modules
Never use as type assertions in normal code; only permit as in a single 'axiomatic' module (brands, constructors, constants) after which types flow safely without casts
Always use exhaustive pattern matching for union types through .exhaustive() or Match.exhaustive() from effect-ts; never use switch statements or unhandled type branches
Use Effect<Success, Error, Requirements> monad from effect-ts for all effects; compose through pipe() and Effect.flatMap(); never use async/await, raw Promise chains (then/catch), or Promise.all in product code
Interoperate with Promise/exceptions only in SHELL through Effect.try/Effect.tryPromise with typed error mapping; never leave raw exceptions or untyped errors in the domain
Use Effect.acquireRelease + Effect.scoped for resource management with guaranteed finalization; never manage resources with try/finally or manual cleanup
All external services (database, HTTP, environment) must be accessed through Effect-based interfaces and Layer-based dependency injection; never call external APIs directly
Provide comprehensive TSDoc comments with mathematical notation: @pure, @effect, @invariant, @precondition, @postcondition, @complexity, @throws, and CHANGE/WHY/REF/SOURCE/FORMAT THEOREM functional comment markers
No console.*, process direct calls, or untyped environment access in product code; all such operations must be abstracted through Layer-based services in SHELL
Boundary data from external sources (HTTP, database, environment) must be decoded/valida...

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/{browser*,server*,app*,*.ts,*.js}

📄 CodeRabbit inference engine (README.md)

Web version must listen on 0.0.0.0 by default for accessibility across LAN devices

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/{cli*,command*,auto*,*.ts,*.tsx}

📄 CodeRabbit inference engine (README.md)

Implement auto-mode agent selection logic to choose Claude, Codex, Gemini, or Grok randomly from available authorized providers, or allow forced selection with --auto=

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**

⚙️ CodeRabbit configuration file

**: РОЛЬ: Математик-программист, специализирующийся на формально верифицируемой функциональной архитектуре.

ЦЕЛЬ: Создавать математически доказуемые решения через функциональную парадигму с полным разделением чистых вычислений и контролируемых эффектов.

МОДЕЛЬ РАССУЖДЕНИЯ:

  • Не выдавать “личные мнения”. Формировать вывод как результат симуляции профессионального обсуждения релевантных ролей
    (архитектор Effect/FP, ревьюер типов, страж CORE↔SHELL, тест-инженер).
  • Если запрос сформулирован как “что думаешь”, отвечать в терминах аргументов ролей и выбирать решение
    по критериям инвариантов, типовой безопасности и тестируемости (если пользователь явно просит выбор — выбрать и обосновать).

ПРАВИЛО ПРОЦЕССА (НЕ ФОРМАТ ОТВЕТА):
В начале работы (внутренне) формулировать Deep Research вопрос:
"I am looking for code that does , is there existing code that can do this?"
Далее:

  • если доступен проект/код — сперва искать и переиспользовать существующие паттерны (минимальный корректный diff),
  • если проект недоступен — опираться на предоставленный контекст и явно фиксировать допущения,
  • код писать только после формального понимания задачи (типы/инварианты → архитектура → код → тесты),
  • источники указывать только если реально использован внешний материал; иначе SOURCE: n/a.

ИНСТРУМЕНТАЛЬНОЕ ПОВЕДЕНИЕ (ОБЯЗАТЕЛЬНО, НЕ ФОРМАТ ОТВЕТА):

  • Агент всегда использует доступные инструменты среды (терминал, поиск по проекту, запуск тестов/скриптов, анализ сборки, web-ресёрч при необходимости)
    для ресёрча, проверки гипотез и выполнения действий. Приоритет: проверяемость, воспроизводимость, минимальный риск.
  • Агент не предлагает “гайд” как замену действия. Если действие возможно выполнить инструментами — агент выполняет его сам,
    затем сообщает, что было сделано и как повторить.
  • Любые инструкции (команды/процедуры) агент даёт только после собственной проверки на доступной среде.
    Если проверить невозможно — явно фиксирует ограничение и перечисляе...

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/openapi/openapi.json
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.

Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.

Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.

Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.

Files:

  • packages/app/src/docker-git/api-client.ts
  • packages/api/src/api/contracts.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/openapi/src/openapi-paths.ts
  • packages/openapi/openapi.json
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
  • packages/api/tests/auth.test.ts
  • packages/api/src/http.ts
  • packages/api/src/api/openapi.ts
  • packages/lib/src/usecases/state-repo/init.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
  • packages/auth-oauth/src/claude-docker-oauth.ts
  • packages/lib/src/usecases/state-repo.ts
  • packages/lib/src/usecases/auth-claude.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx}: Write property-based tests using fast-check (fc.property) to verify mathematical invariants; unit tests must use Effect test utilities without async/await
Every bug fix must be accompanied by a reproducing test case; the test must fail before the fix and pass after; document the Proof of Fix with root cause and solution

Files:

  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/api/tests/openapi.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
  • packages/api/tests/auth.test.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/auth-oauth/tests/claude-docker-oauth.test.ts
**/{.env*,auth*,config*,setup*}

📄 CodeRabbit inference engine (README.md)

Store authentication tokens in env-file as GIT_AUTH_TOKEN__ / GIT_AUTH_USER__

Files:

  • packages/api/tests/auth.test.ts
  • packages/lib/src/usecases/auth-claude-credentials.ts
  • packages/api/src/services/auth.ts
  • packages/lib/tests/usecases/auth-claude-login.test.ts
  • packages/lib/src/usecases/auth-claude.ts
🧠 Learnings (3)
📚 Learning: 2026-05-22T21:08:18.083Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 344
File: packages/app/src/docker-git/controller-compose.ts:34-40
Timestamp: 2026-05-22T21:08:18.083Z
Learning: In this repo’s docker-git controller compose generation, `${DOCKER_GIT_CONTROLLER_BUILD_SKILLER:-1}` should be treated as standard bash parameter expansion: when `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` is unset, it defaults to the string "1". There is no "-1" mode. The runtime contract enforced by `packages/app/src/docker-git/controller-compose.ts` is: unset / "1" / "true" => output "1"; "0" / "false" => output "0". If review code shows branching/behavior for "-1" or any numeric value other than this 0/1 contract, flag it. Also ensure the Dockerfile ARG `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` stays consistent with default `1`.

Applied to files:

  • packages/app/src/docker-git/api-client.ts
  • packages/app/src/docker-git/api-client-auth.ts
  • packages/app/src/docker-git/program-auth.ts
📚 Learning: 2026-06-10T10:21:51.286Z
Learnt from: konard
Repo: ProverCoderAI/docker-git PR: 386
File: packages/app/tests/docker-git/gridland-react-singleton.test.ts:0-0
Timestamp: 2026-06-10T10:21:51.286Z
Learning: In `packages/app/tests/docker-git` tests that inspect the `packages/terminal` workspace (e.g., for React-related versions), remember that `react-dom` is intentionally declared as a `devDependency` in `packages/terminal` (the terminal exports components but does not render to the DOM itself). Therefore, test assertions should not require `react-dom` to appear in `dependencies`; when resolving versions, accept either `dependencies` or `devDependencies` (as `resolveDepVersion` does in `gridland-react-singleton.test.ts`).

Applied to files:

  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/app/tests/docker-git/program-auth.test.ts
📚 Learning: 2026-05-18T07:43:38.131Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 313
File: packages/api/src/services/panel-cloudflare-tunnel.ts:123-135
Timestamp: 2026-05-18T07:43:38.131Z
Learning: In this repo’s ProverCoderAI/docker-git architecture, it is intentional for service modules under packages/api/src/services/ to call Node.js APIs directly (e.g., fs, child_process, fetch). Do not treat direct Node API usage in these service modules as a dependency-injection (DI) violation. This codebase provides the NodeContext at the program boundary (entry point) rather than injecting Context.Tag/Layer services into individual service modules; reviewers should only flag DI/context issues if the expected boundary setup is missing.

Applied to files:

  • packages/api/src/services/auth.ts
🔇 Additional comments (17)
packages/app/src/docker-git/api-client.ts (1)

31-31: LGTM!

packages/app/tests/docker-git/parser-auth.test.ts (1)

53-63: LGTM!

packages/openapi/src/openapi-paths.ts (1)

455-470: LGTM!

Also applies to: 5163-5285

packages/openapi/openapi.json (1)

10458-10758: LGTM!

packages/app/src/docker-git/api-client-auth.ts (1)

25-25: LGTM!

Also applies to: 207-211

packages/app/src/docker-git/program-auth.ts (1)

9-9: LGTM!

Also applies to: 34-58, 82-82, 162-165, 224-224

packages/api/src/api/contracts.ts (1)

302-309: LGTM!

packages/api/tests/openapi.test.ts (1)

35-40: LGTM!

packages/api/src/http.ts (1)

62-62: LGTM!

Also applies to: 1142-1150

packages/api/src/api/openapi.ts (1)

254-267: LGTM!

Also applies to: 618-622

packages/lib/src/usecases/auth-claude-credentials.ts (2)

1-24: LGTM!


35-56: 🩺 Stability & Availability

Комментарий неактуален accountPath создаётся в withClaudeAuth через fs.makeDirectory(accountPath, { recursive: true }) до вызова persistClaudeOauthToken, поэтому fs.makeTempDirectory({ directory: accountPath, ... }) не падает из‑за отсутствующей директории.

			> Likely an incorrect or invalid review comment.
packages/api/src/services/auth.ts (1)

37-41: LGTM!

Also applies to: 68-68, 85-85, 523-563, 585-719

packages/lib/tests/usecases/auth-claude-login.test.ts (1)

311-312: LGTM!

packages/auth-oauth/tests/claude-docker-oauth.test.ts (1)

105-106: LGTM!

packages/lib/src/usecases/state-repo.ts (1)

8-8: LGTM!

Also applies to: 33-33, 46-52, 219-219, 258-258

packages/lib/src/usecases/auth-claude.ts (1)

6-24: LGTM!

Also applies to: 33-44, 179-197

Comment thread packages/api/src/http.ts
Comment on lines +1142 to +1150
HttpRouter.get(
"/auth/claude/status",
Effect.gen(function*(_) {
const request = yield* _(HttpServerRequest.HttpServerRequest)
const label = new URL(request.url, "http://localhost").searchParams.get("label")
const status = yield* _(readClaudeAuthStatus(label))
return yield* _(jsonResponse({ status }, 200))
}).pipe(Effect.catchAll(errorResponse))
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Проверить, есть ли middleware авторизации, оборачивающий /auth маршруты
rg -n "HttpMiddleware|Authorization|authenticate" packages/api/src/http.ts packages/api/src -g '!**/*.test.ts'

Repository: ProverCoderAI/docker-git

Length of output: 1743


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== program.ts outline ==\n'
ast-grep outline packages/api/src/program.ts --view expanded || true

printf '\n== http.ts outline (around auth routes) ==\n'
ast-grep outline packages/api/src/http.ts --view expanded | sed -n '1,220p' || true

printf '\n== auth status routes and middleware references ==\n'
rg -n '"/auth/[^"]+/status"|HttpMiddleware|withMiddlewares|middleware|Auth' packages/api/src/http.ts packages/api/src/program.ts

Repository: ProverCoderAI/docker-git

Length of output: 16514


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== program.ts (lines 1-120) ==\n'
sed -n '1,120p' packages/api/src/program.ts

printf '\n== http.ts (routes around /auth and wrapper) ==\n'
sed -n '1100,1338p' packages/api/src/http.ts

printf '\n== readClaudeAuthStatus definition ==\n'
rg -n "readClaudeAuthStatus|type .*AuthStatus|account" packages/api/src/services packages/api/src -g '!**/*.test.ts'

Repository: ProverCoderAI/docker-git

Length of output: 40037


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== packages/api/src/services/auth.ts (480-540, 708-720) ==\n'
sed -n '480,540p' packages/api/src/services/auth.ts
printf '\n---\n'
sed -n '708,720p' packages/api/src/services/auth.ts

printf '\n== packages/api/src/api/contracts.ts (290-315) ==\n'
sed -n '290,315p' packages/api/src/api/contracts.ts

printf '\n== route/app middleware search ==\n'
rg -n 'HttpMiddleware|serve\\(|withMiddleware|withMiddlewares|HttpServer\\.serve|auth.*middleware|require.*auth|ApiAuthRequiredError' packages/api/src

Repository: ProverCoderAI/docker-git

Length of output: 3284


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== auth / middleware search ==\n'
rg -n 'HttpMiddleware|HttpRouter\.(use|mount|group|prefix|prefixPath)|withMiddlewares|withMiddleware|authorize|authenticated|ApiAuthRequiredError' packages/api/src

printf '\n== makeRouter head and app assembly around withCoreRoutes ==\n'
sed -n '1040,1360p' packages/api/src/http.ts

printf '\n== Claude account extraction ==\n'
sed -n '600,705p' packages/api/src/services/auth.ts

Repository: ProverCoderAI/docker-git

Length of output: 22509


Закрыть /auth/*/status от публичного доступа или убрать account из ответа. В packages/api/src/http.ts:1142-1150 эти маршруты живут без отдельного auth-guard, а readClaudeAuthStatus() может вернуть emailAddress/displayName из локальных credential-файлов; при веб-старте на 0.0.0.0 это раскрывает PII по LAN.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/api/src/http.ts` around lines 1142 - 1150, The `/auth/claude/status`
handler currently exposes auth status without a guard, and
`readClaudeAuthStatus()` can leak `emailAddress`/`displayName` from local
credentials. Protect this route with the same auth check used for other
sensitive `/auth/*` endpoints in `HttpRouter.get`, or remove `account` fields
from the payload returned via `jsonResponse`. Use `readClaudeAuthStatus` and the
existing route registration in `packages/api/src/http.ts` to keep the fix
localized.

Source: Path instructions

Comment on lines +565 to +583
const resolveClaudeAuthMethod = (
fs: FileSystem.FileSystem,
path: Path.Path,
accountPath: string
): Effect.Effect<ClaudeAuthMethod, PlatformError> =>
Effect.gen(function*(_) {
const hasOauthToken = yield* _(readNonEmptyFile(fs, path.join(accountPath, ".oauth-token")))
if (hasOauthToken) {
return "oauth-token"
}

const hasRootCredentials = yield* _(readNonEmptyFile(fs, path.join(accountPath, ".credentials.json")))
if (hasRootCredentials) {
return "claude-ai-session"
}

const hasNestedCredentials = yield* _(readNonEmptyFile(fs, path.join(accountPath, ".claude", ".credentials.json")))
return hasNestedCredentials ? "claude-ai-session" : "none"
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Дублирование resolveClaudeAuthMethod между packages/api/src/services/auth.ts и packages/lib/src/usecases/auth-claude-credentials.ts.

Здесь реализована собственная (read-only) версия определения метода Claude-аутентификации, при том что packages/lib/src/usecases/auth-claude-credentials.ts уже содержит функцию с тем же именем и почти той же логикой (.oauth-token → root .credentials.json → nested .claude/.credentials.json), но с побочными эффектами (clearClaudeSessionCredentials, syncClaudeCredentialsFile). Поскольку packages/api архитектурно может зависеть от packages/lib (а не наоборот — согласно README: "API работает только с LIB"), знание о наборе путей-кандидатов для проверки метода дублируется в двух местах без единого источника истины: если в lib добавится новый fallback-путь или изменится порядок проверки, services/auth.ts можно легко забыть обновить, и статус в API начнёт расходиться с реальным поведением CLI.

Предлагается вынести в auth-claude-credentials.ts чистую (без побочных эффектов) функцию вида detectClaudeAuthMethod(fs, accountPath): Effect<ClaudeAuthMethod, PlatformError>, которую использовали бы обе стороны: resolveClaudeAuthMethod (SHELL, с sync/clear) — вызывая её и затем нормализуя хранение, и readClaudeAuthStatus здесь — вызывая её напрямую без побочных эффектов.

Как указано в coding guidelines: "Дублирование кода и смысла недопустимо: перед новым кодом — Deep Research по существующим реализациям, одна единица смысла — одно место определения."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/api/src/services/auth.ts` around lines 565 - 583,
`resolveClaudeAuthMethod` in `packages/api/src/services/auth.ts` duplicates the
Claude auth detection logic already present in
`packages/lib/src/usecases/auth-claude-credentials.ts`, so the source of truth
is split. Extract a shared pure detector (for example,
`detectClaudeAuthMethod(fs, accountPath)`) in the lib usecase and have both the
API-side `resolveClaudeAuthMethod` and the existing lib
`resolveClaudeAuthMethod` call it, keeping the side-effectful sync/clear
behavior only in the lib wrapper.

Source: Coding guidelines

logoutCodexAuth,
logoutGitAuth,
logoutGrokAuth,
readClaudeAuthStatus,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Тесты логически верны, но отсутствуют property-based тесты.

Новые тесты для readClaudeAuthStatus корректно проверяют все ветки (oauth-token, root/nested claude-ai-session, none), а также отсутствие секрета токена в сериализованном статусе (строка 548). Однако не добавлено ни одного property-based теста через fc.property для инвариантов вида connected === (method !== "none") или идемпотентности нормализации label.

Как указано в coding guidelines: "Write property-based tests using fast-check (fc.property) to verify mathematical invariants".

Also applies to: 518-634

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/api/tests/auth.test.ts` at line 22, Add property-based coverage for
readClaudeAuthStatus using fast-check, since the current tests only cover fixed
branches and serialization. Extend the auth.test.ts suite with fc.property-based
tests around the readClaudeAuthStatus flow to validate invariants like connected
matching method !== "none" and label normalization being idempotent. Use the
existing readClaudeAuthStatus test setup and keep the new properties focused on
the returned status shape so they complement the current branch tests without
duplicating them.

Source: Coding guidelines

Comment on lines +1 to +15
import { describe, expect, it } from "vitest"

import { isRoutedAuthCommand } from "../../src/docker-git/program-auth.js"

describe("program auth routing", () => {
it("routes Claude status through the controller in host API mode", () => {
expect(
isRoutedAuthCommand({
_tag: "AuthClaudeStatus",
label: null,
claudeAuthPath: ".docker-git/.orch/auth/claude"
})
).toBe(true)
})
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Тест написан в обычном стиле vitest, а не через Effect test utilities.

Файл целиком новый и тестирует isRoutedAuthCommand, используя it напрямую из vitest, без Effect-обёртки — в отличие от соседнего parser-auth.test.ts, где аналогичные тесты оформлены через it.effect + Effect.sync.

As per coding guidelines, **/*.test.{ts,tsx}: "unit tests must use Effect test utilities without async/await".

♻️ Пример приведения к стилю Effect (уточните точный импорт `it.effect`, используемый в parser-auth.test.ts)
-import { describe, expect, it } from "vitest"
+import { describe, expect } from "vitest"
+import { Effect } from "effect"
+// используйте тот же источник `it.effect`, что и в parser-auth.test.ts
+import { it } from "`@effect/vitest`"

 import { isRoutedAuthCommand } from "../../src/docker-git/program-auth.js"

 describe("program auth routing", () => {
-  it("routes Claude status through the controller in host API mode", () => {
-    expect(
-      isRoutedAuthCommand({
-        _tag: "AuthClaudeStatus",
-        label: null,
-        claudeAuthPath: ".docker-git/.orch/auth/claude"
-      })
-    ).toBe(true)
-  })
+  it.effect("routes Claude status through the controller in host API mode", () =>
+    Effect.sync(() => {
+      expect(
+        isRoutedAuthCommand({
+          _tag: "AuthClaudeStatus",
+          label: null,
+          claudeAuthPath: ".docker-git/.orch/auth/claude"
+        })
+      ).toBe(true)
+    }))
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { describe, expect, it } from "vitest"
import { isRoutedAuthCommand } from "../../src/docker-git/program-auth.js"
describe("program auth routing", () => {
it("routes Claude status through the controller in host API mode", () => {
expect(
isRoutedAuthCommand({
_tag: "AuthClaudeStatus",
label: null,
claudeAuthPath: ".docker-git/.orch/auth/claude"
})
).toBe(true)
})
})
import { describe, expect } from "vitest"
import { Effect } from "effect"
import { it } from "`@effect/vitest`"
import { isRoutedAuthCommand } from "../../src/docker-git/program-auth.js"
describe("program auth routing", () => {
it.effect("routes Claude status through the controller in host API mode", () =>
Effect.sync(() => {
expect(
isRoutedAuthCommand({
_tag: "AuthClaudeStatus",
label: null,
claudeAuthPath: ".docker-git/.orch/auth/claude"
})
).toBe(true)
}))
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/tests/docker-git/program-auth.test.ts` around lines 1 - 15, The
new program auth test is using plain vitest `it` instead of the required Effect
test utilities. Update `program-auth.test.ts` to follow the same pattern as
`parser-auth.test.ts` by using `it.effect` with `Effect.sync` (and the matching
Effect imports) around the `isRoutedAuthCommand` assertion, while keeping the
test synchronous and free of async/await.

Source: Coding guidelines


export const defaultClaudeDockerOauthImage = "docker-git-auth-claude:latest"
export const defaultClaudeDockerOauthContainerHome = "/claude-home"
const claudeDockerOauthProbeConfigDir = "/claude-probe-home"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Сделайте probe HOME writable для non-root Docker runs.

/claude-probe-home находится в корне FS; при запуске с поддерживаемым --user Claude не сможет создать HOME/CLAUDE_CONFIG_DIR, и probe даст ложный auth failure. Верните путь в writable область вроде /tmp/... либо создавайте/chown-ьте каталог через tmpfs/entrypoint перед probe.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/auth-oauth/src/claude-docker-oauth.ts` at line 21, The
claudeDockerOauthProbeConfigDir constant currently points to a root-level path
that may not be writable for non-root Docker runs, causing the probe to fail
when Claude tries to create HOME or CLAUDE_CONFIG_DIR. Update
claudeDockerOauthProbeConfigDir in claude-docker-oauth.ts to use a writable
location such as a /tmp-based directory, or ensure the directory is created and
owned appropriately before the probe runs in the claudeDockerOauth flow.

Comment on lines +58 to +95
const syncClaudeCredentialsFile = (
fs: FileSystem.FileSystem,
path: Path.Path,
accountPath: string
): Effect.Effect<void, PlatformError> =>
Effect.gen(function*(_) {
const nestedPath = claudeNestedCredentialsPath(accountPath)
const rootPath = claudeCredentialsPath(accountPath)
const isNestedExists = yield* _(isRegularFile(fs, nestedPath))
if (isNestedExists) {
const nestedText = yield* _(readFileStringIfPresent(fs, nestedPath))
if (nestedText !== null) {
yield* _(writeFileStringEnsuringParent(fs, path, rootPath, nestedText))
yield* _(fs.chmod(rootPath, 0o600), Effect.orElseSucceed(() => void 0))
}
return
}

const isRootExists = yield* _(isRegularFile(fs, rootPath))
if (isRootExists) {
const rootText = yield* _(readFileStringIfPresent(fs, rootPath))
if (rootText === null) {
return
}
yield* _(writeFileStringEnsuringParent(fs, path, nestedPath, rootText))
yield* _(fs.chmod(nestedPath, 0o600), Effect.orElseSucceed(() => void 0))
}
})

const clearClaudeSessionCredentials = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<void, PlatformError> =>
Effect.gen(function*(_) {
yield* _(fs.remove(claudeCredentialsPath(accountPath), { force: true }))
yield* _(fs.remove(claudeNestedCredentialsPath(accountPath), { force: true }))
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

resolveClaudeAuthMethod — misleading имя: функция "resolve" имеет побочные эффекты.

resolveClaudeAuthMethod (строки 126-141) не просто читает состояние — она вызывает clearClaudeSessionCredentials и syncClaudeCredentialsFile, которые удаляют/переписывают файлы credentials на диске. Именно из-за этих побочных эффектов пришлось писать отдельную read-only копию логики в packages/api/src/services/auth.ts (см. комментарий там) — это прямое следствие того, что имя функции не отражает её реального поведения (SHELL-эффект скрыт за именем в стиле "resolve"/query).

Предлагается переименовать в что-то вида normalizeAndResolveClaudeAuthMethod, а также добавить функциональные комментарии (PURITY: SHELL, EFFECT, INVARIANT) для syncClaudeCredentialsFile, clearClaudeSessionCredentials и resolveClaudeAuthMethod, как это уже сделано для persistClaudeOauthToken (строки 25-34).

Как указано в coding guidelines: функции SHELL-слоя должны иметь маркировку PURITY: SHELL и явное описание эффекта; имя должно однозначно отражать поведение.

Also applies to: 126-141

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/auth-claude-credentials.ts` around lines 58 - 95,
The naming of resolveClaudeAuthMethod is misleading because it performs
filesystem side effects via syncClaudeCredentialsFile and
clearClaudeSessionCredentials instead of only resolving state. Rename the
function to reflect the normalize-and-resolve behavior, and add functional
comments marking syncClaudeCredentialsFile, clearClaudeSessionCredentials, and
the renamed resolver as PURITY: SHELL with a short EFFECT/invariant note,
consistent with persistClaudeOauthToken. Keep the behavior unchanged; just make
the side effects explicit in the symbol names and comments.

Source: Coding guidelines

Comment on lines +96 to +124
const hasNonEmptyOauthToken = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<boolean, PlatformError> =>
Effect.gen(function*(_) {
const tokenPath = claudeOauthTokenPath(accountPath)
const hasToken = yield* _(isRegularFile(fs, tokenPath))
if (!hasToken) {
return false
}
const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
return tokenText.trim().length > 0
})

export const readOauthToken = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<string | null, PlatformError> =>
Effect.gen(function*(_) {
const tokenPath = claudeOauthTokenPath(accountPath)
const hasToken = yield* _(isRegularFile(fs, tokenPath))
if (!hasToken) {
return null
}

const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
const token = tokenText.trim()
return token.length > 0 ? token : null
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Дублирование логики между hasNonEmptyOauthToken и readOauthToken.

Обе функции читают claudeOauthTokenPath(accountPath), проверяют isRegularFile, читают файл и делают trim(). hasNonEmptyOauthToken можно выразить через readOauthToken.

♻️ Устранение дублирования
-const hasNonEmptyOauthToken = (
-  fs: FileSystem.FileSystem,
-  accountPath: string
-): Effect.Effect<boolean, PlatformError> =>
-  Effect.gen(function*(_) {
-    const tokenPath = claudeOauthTokenPath(accountPath)
-    const hasToken = yield* _(isRegularFile(fs, tokenPath))
-    if (!hasToken) {
-      return false
-    }
-    const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
-    return tokenText.trim().length > 0
-  })
-
-export const readOauthToken = (
+export const readOauthToken = (
   fs: FileSystem.FileSystem,
   accountPath: string
 ): Effect.Effect<string | null, PlatformError> =>
   Effect.gen(function*(_) {
     const tokenPath = claudeOauthTokenPath(accountPath)
     const hasToken = yield* _(isRegularFile(fs, tokenPath))
     if (!hasToken) {
       return null
     }
 
     const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
     const token = tokenText.trim()
     return token.length > 0 ? token : null
   })
+
+const hasNonEmptyOauthToken = (
+  fs: FileSystem.FileSystem,
+  accountPath: string
+): Effect.Effect<boolean, PlatformError> =>
+  readOauthToken(fs, accountPath).pipe(Effect.map((token) => token !== null))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const hasNonEmptyOauthToken = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<boolean, PlatformError> =>
Effect.gen(function*(_) {
const tokenPath = claudeOauthTokenPath(accountPath)
const hasToken = yield* _(isRegularFile(fs, tokenPath))
if (!hasToken) {
return false
}
const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
return tokenText.trim().length > 0
})
export const readOauthToken = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<string | null, PlatformError> =>
Effect.gen(function*(_) {
const tokenPath = claudeOauthTokenPath(accountPath)
const hasToken = yield* _(isRegularFile(fs, tokenPath))
if (!hasToken) {
return null
}
const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
const token = tokenText.trim()
return token.length > 0 ? token : null
})
export const readOauthToken = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<string | null, PlatformError> =>
Effect.gen(function*(_) {
const tokenPath = claudeOauthTokenPath(accountPath)
const hasToken = yield* _(isRegularFile(fs, tokenPath))
if (!hasToken) {
return null
}
const tokenText = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
const token = tokenText.trim()
return token.length > 0 ? token : null
})
const hasNonEmptyOauthToken = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<boolean, PlatformError> =>
readOauthToken(fs, accountPath).pipe(Effect.map((token) => token !== null))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/auth-claude-credentials.ts` around lines 96 - 124,
`hasNonEmptyOauthToken` duplicates the same token lookup and normalization logic
already implemented in `readOauthToken`. Refactor `hasNonEmptyOauthToken` to
delegate to `readOauthToken(fs, accountPath)` and return a boolean based on
whether it yields a non-null value, keeping the filesystem/file checks and
trimming behavior centralized in `readOauthToken`.

const hasCredentials = yield* _(isRegularFile(fs, claudeCredentialsPath(accountPath)))
return hasCredentials ? "claude-ai-session" : "none"
})
const claudeProbeConfigDir = "/claude-probe-home"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Не используйте top-level probe config dir без подготовки прав.

Этот путь используется login/status probe; если Docker запускается non-root, /claude-probe-home нельзя создать/записать, и статус OAuth станет ложно negative. Синхронизируйте фикс с packages/auth-oauth/src/claude-docker-oauth.ts: writable /tmp/... либо явное создание/chown/tmpfs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/auth-claude.ts` at line 49, The hardcoded
claudeProbeConfigDir in auth-claude.ts should not point to a top-level path that
may be unwritable for non-root Docker runs. Update the probe config directory
setup to match claude-docker-oauth.ts by using a writable /tmp-based location or
by explicitly creating and preparing the directory with the right
ownership/permissions before login/status probes use it.

Effect.gen(function*(_) {
const fs = yield* _(FileSystem.FileSystem)
const path = yield* _(Path.Path)
const root = resolveStateRoot(path, process.cwd())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Уберите прямой process.cwd() из Effect-оркестрации.

Line 114 читает процесс напрямую внутри usecase-слоя. Передавайте cwd из shell-boundary/сервиса окружения, чтобы эффект оставался управляемым и тестируемым. As per coding guidelines, "No console.*, process direct calls, or untyped environment access in product code; all such operations must be abstracted through Layer-based services in SHELL".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/state-repo/init.ts` at line 114, The init usecase
is reading the current working directory directly via process.cwd(), which
should be removed from Effect orchestration. Update the init flow around
resolveStateRoot so cwd is injected from the shell boundary or an environment
service passed into the usecase, and use that value instead of calling
process.cwd() inside product code. Keep the dependency explicit through the
existing init/usecase entrypoint and related service boundary so the logic
remains testable and Layer-based.

Source: Coding guidelines

Comment on lines +122 to +123
yield* _(Effect.log(`State dir ready: ${root}`))
yield* _(Effect.log(`Remote: ${input.repoUrl}`))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Не логируйте абсолютный state path и raw remote URL.

root обычно содержит пользовательский home path, а input.repoUrl может включать embedded token/userinfo. Логируйте обезличенный alias и редактированный remote без credentials.

Возможный минимальный фикс
-      yield* _(Effect.log(`State dir ready: ${root}`))
-      yield* _(Effect.log(`Remote: ${input.repoUrl}`))
+      yield* _(Effect.log("State dir ready"))
+      yield* _(Effect.log("Remote configured"))

As per coding guidelines, "Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
yield* _(Effect.log(`State dir ready: ${root}`))
yield* _(Effect.log(`Remote: ${input.repoUrl}`))
yield* _(Effect.log("State dir ready"))
yield* _(Effect.log("Remote configured"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/lib/src/usecases/state-repo/init.ts` around lines 122 - 123, The
logging in the state repo initialization leaks sensitive information by printing
the absolute state directory and the raw remote URL. Update the logging around
the init flow in the state-repo usecase (the Effect.log calls in init) to use a
non-identifying alias for the state location and a redacted remote string that
removes credentials/userinfo from input.repoUrl. Keep the log context useful,
but avoid exposing root or any embedded tokens in the remote output.

Source: Coding guidelines

@skulidropek

skulidropek commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

AI Session Backup

Commit: 84b2b29
Status: success
Files: 8 (10.69 MB)
Links: README | Manifest

git status

On branch pr-440
Your branch is up to date with 'origin/pr-440'.

nothing to commit, working tree clean

@skulidropek skulidropek marked this pull request as ready for review July 2, 2026 07:12
@skulidropek skulidropek merged commit 20e51ca into ProverCoderAI:main Jul 2, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants